/*
 * @Author: DaTree
 * @Date: 2020-11-18 09:03:48
 * @LastEditTime: 2020-11-19 22:33:05
 * @LastEditors: DaTree
 * @Description: DaTreeEdit
 * @FilePath: \services\src\utils\ssh2.js
 * @天将降大任于是人也，必先苦其心志，劳其筋骨，饿其体肤，空乏其身，行拂乱其所为。 ——《孟子•告子下》
 * @symbol_custom_string_obkoro1_copyright: Copyright ${now_year} DaTree
 */
"use strict"
import ssh2 from 'ssh2'
import util from 'util'
import events from "events"
import fs from "fs"
import path from 'path'
/**
 * 连接对象类
 */
class SSH2ServerConfig {
  // host: '192.168.36.130',
  // port: 22,
  // username: 'root',
  // password: 'aliOS1688'
  // privateKey: require('fs').readFileSync('/here/is/my/key')
  constructor(options) {
    this.host = options.host
    this.port = options.port
    this.username = options.username
    this.password = options.password
    this.privateKey = options.privateKey
  }

}
export { SSH2ServerConfig }

/**
* 描述：控制上传或者下载一个一个的执行
*/
function Control () {
  events.EventEmitter.call(this);
}
util.inherits(Control, events.EventEmitter); // 使这个类继承EventEmitter
/**
 * ssh操作类
 */
export default class SSH2 {
  constructor(options) {
    this.config = options
    this.conn = null
    // 控制器
    let control = new Control();
    control.on("donext", function (todos, then) {
      if (todos.length > 0) {
        let func = todos.shift();
        func(function (err, result) {
          if (err) {
            throw err;
          } else {
            control.emit("donext", todos, then);
          }
        });
      } else {
        then(null);
      }
    });
    this.control = control
  }
  /**
   * 描述：连接远程电脑
   * 参数：server 远程电脑凭证；then 回调函数
   * @param {*} then 回调：then(conn) 连接远程的client对象
   */
  connect (then) {
    // const me = this
    let conn = new ssh2.Client();
    console.log(this.config)
    conn.on("ready", () => {
      this.conn = conn;
      then(true);
    }).on('error', (err) => {
      console.log("connect error!");
      then(false);
    }).on('end', () => {
      console.log("connect end!");
    }).on('close', (had_error) => {
      console.log("connect close");
    }).connect(this.config);
  }
  /**
   * 关闭连接
   */
  close () {
    if (this.conn !== null) {
      this.conn.end();
      this.conn.destroy();
    }
  }
  /**
  * 描述：运行shell命令
  * 参数：cmd 执行的命令；then 回调函数
  * 回调：then(err, data) ： data 运行命令之后的返回数据信息
  */
  shell (cmd, then, ondata) {
    this.conn.shell(function (err, stream) {
      if (err) throw err;
      stream.on('close', function () {
        // console.log('Stream :: close');
        // me.close()
        then()
      }).on('data', function (data) {
        ondata('' +data)
      });
      stream.end(cmd);

      // if (err) {
      //   then(err);
      // } else {// end of if
      //   var buf = "";
      //   stream.on('close', function () {
      //     me.close()
      //     // conn.end();
      //     then(err, buf);
      //   }).on('data', function (data) {
      //     buf = buf + data;
      //   }).stderr.on('data', function (data) {
      //     console.log('stderr: ' + data);
      //   });
      //   stream.end(cmd);
      // }
    });
  }
  /**
  * 描述：上传文件
  * 参数：localPath 本地路径；remotePath 远程路径；then 回调函数
  * 回调：then(err, result)
  */
  uploadFile (localPath, remotePath, then) {
    this.conn.sftp(function (err, sftp) {
      if (err) {
        then(err);
      } else {
        sftp.fastPut(localPath, remotePath, function (err, result) {
          then(err, result);
        });
      }
    });
  }
  /**
  * 描述：下载文件
  * 参数：remotePath 远程路径；localPath 本地路径；then 回调函数
  * 回调：then(err, result)
  */
  downloadFile (remotePath, localPath, then) {
    this.conn.sftp(function (err, sftp) {
      if (err) {
        then(err);
      } else {
        sftp.fastGet(remotePath, localPath, function (err, result) {
          if (err) {
            then(err);
          } else {
            // conn.end();
            then(err, result);
          }
        });
      }
    });
  }

  /**
  * 描述：获取远程文件路径下文件列表信息
  * 参数：
  *	remotePath 远程路径；
  *	isFile 是否是获取文件，true获取文件信息，false获取目录信息；
  *	then 回调函数
  * 回调：then(err, dirs) ： dir, 获取的列表信息
  */
  getFileOrDirList (remotePath, isFile, then) {
    let cmd = "find " + remotePath + " -type " + (isFile == true ? "f" : "d") + "\r\nexit\r\n";
    this.shell(cmd, function (err, data) {
      let arr = [];
      let remoteFile = [];
      arr = data.split("\r\n");
      arr.forEach(function (dir) {
        if (dir.indexOf(remotePath) == 0) {
          remoteFile.push(dir);
        }
      });
      then(err, remoteFile);
    });
  }
  /**
  * 描述：下载目录到本地
  * 参数：server 远程电脑凭证；
  *	remotePath 远程路径；
  *	localDir 本地路径，
  *	then 回调函数
  * 回调：then(err)
  */
  downloadDir (remoteDir, localDir, then) {
    this.getFileOrDirList(remoteDir, false, function (err, dirs) {
      if (err) {
        throw err;
      } else {
        this.getFileOrDirList(remoteDir, true, function (err, files) {
          if (err) {
            throw err;
          } else {
            dirs.shift();
            dirs.forEach(function (dir) {
              let tmpDir = path.join(localDir, dir.slice(remoteDir.length + 1)).replace(/[//]\g/, '\\');
              // 创建目录
              fs.mkdirSync(tmpDir);
            });
            let todoFiles = [];
            files.forEach(function (file) {
              let tmpPath = path.join(localDir, file.slice(remoteDir.length + 1)).replace(/[//]\g/, '\\');
              todoFiles.push(function (done) {
                this.downloadFile(server, file, tmpPath, done);
                console.log("downloading the " + file);
              });// end of todoFiles.push						
            });
            this.control.emit("donext", todoFiles, then);
          }
        });
      }
    });
  }
  /**
  * 描述：获取windows上的文件目录以及文件列表信息
  * 参数：destDir 本地路径，
  *		dirs 目录列表
  *		files 文件列表
  */
  getFileAndDirList (localDir, dirs, files) {
    let dir = fs.readdirSync(localDir);
    for (let i = 0; i < dir.length; i++) {
      let p = path.join(localDir, dir[i]);
      let stat = fs.statSync(p);
      if (stat.isDirectory()) {
        dirs.push(p);
        this.getFileAndDirList(p, dirs, files);
      } else {
        files.push(p);
      }
    }
  }
  /**
  * 描述：上传文件夹到远程目录
  * 参数：server 远程电脑凭证；
  *		localDir 本地路径，
  *		remotePath 远程路径；
  *		then 回调函数
  * 回调：then(err)
  */
  uploadDir (localDir, remoteDir, then) {
    let dirs = [];
    let files = [];
    this.getFileAndDirList(localDir, dirs, files);

    // 创建远程目录
    let todoDir = [];
    dirs.forEach(function (dir) {
      todoDir.push(function (done) {
        let to = path.join(remoteDir, dir.slice(localDir.length + 1)).replace(/[\\]/g, '/');
        let cmd = "mkdir -p " + to + "\r\nexit\r\n";
        console.log(cmd);
        this.shell(cmd, done);
      })// end of push
    });

    // 上传文件
    let todoFile = [];
    files.forEach(function (file) {
      todoFile.push(function (done) {
        let to = path.join(remoteDir, file.slice(localDir.length + 1)).replace(/[\\]/g, '/');
        console.log("upload " + to);
        this.uploadFile(server, file, to, done);
      });
    });

    this.control.emit("donext", todoDir, function (err) {
      if (err) {
        throw err;
      } else {
        this.control.emit("donext", todoFile, then);
      }
    });
  }
}
